package fr.dauphine.bookstore.modele;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.CollectionOfElements;
import org.hibernate.annotations.MapKeyManyToMany;

/**
 * Livre.
 */
@Entity
public final class Book extends Persistent {

	/**
	 * Serial version UID.
	 */
	private static final long serialVersionUID = -6077710103474403578L;

	/**
	 * Taille max d'une photo (en octets).
	 */
	public static final int PHOTO_MAX_SIZE = 100000;

	/**
	 * Titre.
	 */
	private String title;

	/**
	 * Categorie.
	 */
	private Category category;

	/**
	 * Prix.
	 */
	private BigDecimal price;

	/**
	 * Date.
	 */
	private Date date;

	/**
	 * Auteurs.
	 */
	private List<Author> authors = new ArrayList<Author>();

	/**
	 * Photo.
	 */
	private byte[] photo;
	
	/**
	 * Commandes et leurs quantites.
	 */
	private Map<Order, Integer> orders = new HashMap<Order, Integer>();
	
	// Methodes Get&Set

	/**
	 * Retourne le titre.
	 *
	 * @return Titre
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * Met a jour le titre.
	 *
	 * @param title
	 *            Titre
	 */
	public void setTitle(final String title) {
		this.title = title;
	}

	/**
	 * Retourne la categorie.
	 *
	 * @return Categorie
	 */
	@ManyToOne
	public Category getCategory() {
		return category;
	}

	/**
	 * Met a jour la categorie.
	 *
	 * @param category
	 *            Categorie
	 */
	public void setCategory(final Category category) {
		this.category = category;
	}

	/**
	 * Retourne le prix.
	 *
	 * @return Prix
	 */
	public BigDecimal getPrice() {
		return price;
	}

	/**
	 * Met a jour le prix.
	 *
	 * @param price
	 *            Prix
	 */
	public void setPrice(final BigDecimal price) {
		this.price = price;
	}

	/**
	 * Retourne la date.
	 *
	 * @return Date
	 */
	public Date getDate() {
		return date;
	}

	/**
	 * Met a jour la date.
	 *
	 * @param date
	 *            Date
	 */
	public void setDate(final Date date) {
		this.date = date;
	}

	/**
	 * Retourne les auteurs.
	 *
	 * @return Auteurs
	 */
	@ManyToMany(targetEntity = Author.class)
	public List<Author> getAuthors() {
		return authors;
	}

	/**
	 * Met a jour les auteurs.
	 *
	 * @param authors
	 *            Auteurs
	 */
	public void setAuthors(final List<Author> authors) {
		this.authors = authors;
	}

	/**
	 * Retourne la photo.
	 *
	 * @return Photo
	 */
	@Lob
	@Column(length = PHOTO_MAX_SIZE)
	public byte[] getPhoto() {
		return photo;
	}

	/**
	 * Met a jour la photo.
	 *
	 * @param photo
	 *            Photo
	 */
	public void setPhoto(final byte[] photo) {
		this.photo = photo;
	}
	
	/**
	 * Retourne les commandes et leurs quantites.
	 * 
	 * @return Commandes et leurs quantites
	 */
	@JoinTable(name = "OrderLine")
	@CollectionOfElements
	@MapKeyManyToMany(targetEntity = Order.class, joinColumns = {@JoinColumn(name = "BookstoreOrder_id") })
	@Column(name = "quantity")
	public Map<Order, Integer> getOrders() {
		return orders;
	}

	/**
	 * Met a jour les commandes et leurs quantites.
	 * 
	 * @param orders
	 *            Commandes et leurs quantites
	 */
	public void setOrders(final Map<Order, Integer> orders) {
		this.orders = orders;
	}

	// Methodes Add

	/**
	 * Ajoute un auteur.
	 *
	 * @param author
	 *            Auteur
	 */
	public void addAuthor(final Author author) {
		author.getBooks().add(this);
		getAuthors().add(author);
	}

	// Surcharges

	/**
	 * @return Titre
	 */
	public String toString() {
		return getTitle();
	}
	
	/**
	 * Teste l'egalite avec un objet quelconque.
	 * 
	 * @param that
	 *            Objet quelconque
	 * @return Vrai si l'objet that est egal a l'objet courant, faux sinon
	 */
	public boolean equals(final Object that) {
		return (that != null && that instanceof Book && equals((Book) that));
	}
}
